/*
 * Visual.java
 *
 * Created on December 6, 2006, 6:29 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package org.netbeans.modules.manifesteditor.editor;

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.Image;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.jar.Manifest;
import java.util.logging.Level;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.StyledDocument;
import org.netbeans.core.spi.multiview.CloseOperationState;
import org.netbeans.core.spi.multiview.MultiViewDescription;
import org.netbeans.core.spi.multiview.MultiViewElement;
import org.netbeans.core.spi.multiview.MultiViewElementCallback;
import org.netbeans.modules.manifesteditor.*;
import org.openide.awt.Mnemonics;
import org.openide.explorer.ExplorerManager;
import org.openide.explorer.propertysheet.PropertySheet;
import org.openide.explorer.view.ChoiceView;
import org.openide.nodes.Node;
import org.openide.text.NbDocument;
import org.openide.util.HelpCtx;
import org.openide.util.Lookup;
import org.openide.util.NbBundle;
import org.openide.windows.TopComponent;

/**
 *
 * @author Geertjan Wielenga
 */

public class ManifestVisualView extends JPanel
        implements MultiViewDescription, MultiViewElement, ExplorerManager.Provider,
        PropertyChangeListener, DocumentListener, ManifestDataNode.ChangeCallback {
    
    private ExplorerManager em;
    private ManifestEditorSupport support;
    private PropertySheet sheet;
    
    public ManifestVisualView(ManifestEditorSupport ed) {
        support = ed;
    }
    
    public int getPersistenceType() {
        return TopComponent.PERSISTENCE_ONLY_OPENED;
    }
    
    public String getDisplayName() {
        return "Visual";
    }
    
    public Image getIcon() {
        return null;
    }
    
    public HelpCtx getHelpCtx() {
        return HelpCtx.DEFAULT_HELP;
    }
    
    public String preferredID() {
        return "visual";
    }
    
    public MultiViewElement createElement() {
        assert EventQueue.isDispatchThread();
        
        em = new ExplorerManager();
        em.addPropertyChangeListener(this);
        
        ChoiceView view = new ChoiceView();
        this.setLayout(new BorderLayout());
        JLabel l = new JLabel();
        Mnemonics.setLocalizedText(l, NbBundle.getMessage(ManifestEditorSupport.class, "LBL_Sections"));
        l.setLabelFor(view);
        l.setBorder(BorderFactory.createEmptyBorder(0, 8, 0, 8));
        this.add(BorderLayout.WEST, l);
        this.add(BorderLayout.CENTER, view);
        sheet = new PropertySheet();
        try {
            Manifest mf = new Manifest(support.getInputStream());
            em.setRootContext(ManifestDataNode.createManifestModel(mf, this));
            em.setSelectedNodes(new Node[] { em.getRootContext().getChildren().getNodes(true)[0] });
            support.openDocument().addDocumentListener(this);
        } catch (Exception ex) {
        }
        
        return this;
    }
    
    public JComponent getVisualRepresentation() {
        return sheet;
    }
    
    public JComponent getToolbarRepresentation() {
        return this;
    }
    
    public Action[] getActions() {
        return support.getDataObject().getNodeDelegate().getActions(false);
    }
    
    public Lookup getLookup() {
        return ((ManifestDataObject)support.getDataObject()).getNodeDelegate().getLookup();
    }
    
    public void componentOpened() {
    }
    
    public void componentClosed() {
    }
    
    public void componentShowing() {
    }
    
    public void componentHidden() {
    }
    
    public void componentActivated() {
    }
    
    public void componentDeactivated() {
    }
    
    public org.openide.awt.UndoRedo getUndoRedo() {
        return null;
    }
    
    public void setMultiViewCallback(MultiViewElementCallback callback) {
    }
    
    public CloseOperationState canCloseElement() {
        return CloseOperationState.STATE_OK;
    }
    
    public ExplorerManager getExplorerManager() {
        return em;
    }
    
    public void propertyChange(PropertyChangeEvent evt) {
        sheet.setNodes(em.getSelectedNodes());
    }
    
    public void insertUpdate(DocumentEvent e) {
        refresh();
    }
    
    public void removeUpdate(DocumentEvent e) {
        refresh();
    }
    
    public void changedUpdate(DocumentEvent e) {
        refresh();
    }
    
    public void refresh() {
        try {
            Manifest mf = new Manifest(support.getInputStream());
            ManifestDataNode.refresh(em.getRootContext(), mf);
        } catch (Exception ex) {
        }
    }
    
    public void change(
            final String section, final String name, final String oldValue, final String newValue
            ) throws IllegalArgumentException {
        final StyledDocument d = support.getDocument();
        if (d == null) {
            throw new IllegalArgumentException("document is null");
        }
        
        
        class Ch implements Runnable {
            public void run() {
                try {
                    String text = d.getText(0, d.getLength());
                    
                    int beginSection;
                    int endSection;
                    
                    if ("Main".equals(section)) {
                        beginSection = 0;
                    } else {
                        Matcher m = Pattern.compile("Name:.*" + section).matcher(text);
                        if (!m.find()) {
                            throw new IllegalArgumentException("Section not found");
                        }
                        beginSection = m.start();
                    }
                    endSection = text.indexOf("\n\n", beginSection);
                    
                    if (endSection == -1) {
                        endSection = d.getLength();
                    }
                    
                    String sec = text.substring(beginSection, endSection);
                    Matcher line = Pattern.compile(name + ".*:.*" + oldValue).matcher(sec);
                    if (!line.find()) {
                        throw new IllegalArgumentException("Value definition not found in: " + sec);
                    }
                    
                    int offset = beginSection + line.start();
                    d.remove(offset, line.end() - line.start());
                    d.insertString(offset, name + ": " + newValue, null);
                } catch (BadLocationException ex) {
                    throw new IllegalArgumentException(ex);
                }
            }
        }
        
        
        try {
            Ch ch = new Ch();
            d.removeDocumentListener(this);
            NbDocument.runAtomic(d, ch);
            refresh();
        } finally {
            d.addDocumentListener(this);
        }
    }
}
